#include "stdlib.hpp"
#include <purewell/blob.hpp>
#include <purewell/system.hpp>

namespace purewell
{

PWBlob::~PWBlob()
{
	if ( NULL != m_buf )
	{
		::free(m_buf);
		m_buf = NULL;
	}
}

PWBlob::PWBlob()
: m_buf(NULL), m_size(0)
{
}

PWBlob::PWBlob(size_t blen)
: m_buf(NULL), m_size(0)
{
	allocate(blen);
}

PWBlob::PWBlob(char c, size_t blen)
: m_buf(NULL), m_size(0)
{
	allocate(c, blen);
}

PWBlob::PWBlob(const char* buf, size_t blen)
: m_buf(NULL), m_size(0)
{
	allocate(buf, blen);
}

PWBlob::PWBlob(const std::string& s)
: m_buf(NULL), m_size(0)
{
	allocate(s);
}

PWBlob::PWBlob(const PWBlob& blob)
{
	allocate(blob);
}

bool
PWBlob::isReady(void) const
{
	return NULL != m_buf;
}

bool
PWBlob::isReady(size_t len) const
{
	return len <= m_size && m_buf != NULL;
}

void
PWBlob::swap(PWBlob& blob)
{
	std::swap(m_buf, blob.m_buf);
	std::swap(m_size, blob.m_size);
}

bool
PWBlob::allocate(size_t size)
{
	char* buf((char*)malloc(size));
	if ( NULL == buf )
	{
		return false;
	}

	free();
	m_buf = buf;
	m_size = size;

	return true;
}

bool
PWBlob::allocate(char c, size_t size)
{
	if ( !allocate(size) ) return false;
	memset(m_buf, c, size);
	return true;
}

bool
PWBlob::allocate(const char* buf, size_t blen)
{
	if ( !allocate(blen) ) return false;
	memcpy(m_buf, buf, blen);
	return true;
}

bool
PWBlob::allocate(const PWBlob& blob)
{
	if ( !allocate(blob.m_size) ) return false;
	memcpy(m_buf, blob.m_buf, m_size);
	return true;
}

bool
PWBlob::allocate(const std::string& s)
{
	return allocate(s.c_str(), s.size()+1);
}

bool
PWBlob::reallocate(size_t size)
{
	char* buf((char*)realloc(m_buf, size));
	if ( NULL == buf )
	{
		return false;
	}

	m_buf = buf;
	m_size = size;

	return true;
}

void
PWBlob::free(void)
{
	if ( NULL != m_buf )
	{
		::free(m_buf);
		m_buf = NULL;
	}

	m_size = 0;
}

bool
PWBlob::assign(const char* buf, size_t blen)
{
	if ( m_size < blen ) return false;
	memcpy(m_buf, buf, blen);
	return true;
}

bool
PWBlob::assign(size_t spos, const char* buf, size_t blen)
{
	if ( m_size <= spos ) return false;
	if ( m_size - spos < blen ) return false;

	memcpy(m_buf+spos, buf, blen);
	return true;
}

bool
PWBlob::assign(char c, size_t spos, size_t size)
{
	if ( m_size <= spos ) return false;

	if ( size == (size_t)-1 )
	{
		size = m_size - spos;
	}
	else if ( m_size - spos < size )
	{
		return false;
	}

	memset(m_buf+spos, c, size);
	return true;
}

bool
PWBlob::assign(const std::string& s)
{
	return assign(s.c_str(), s.size()+1);
}

bool
PWBlob::assign(size_t spos, const std::string& s, size_t dspos, size_t size)
{
	if ( size == (size_t)-1 )
	{
		size = s.size()+1 - dspos;
	}

	return assign(spos, s.c_str()+dspos, size);
}

PWBlob&
PWBlob::operator = (const PWBlob& blob)
{
	size_t cplen(blob.m_size);
	char* buf((char*)malloc(cplen));

	if ( NULL == buf )
	{
		return *this;
	}

	memcpy(buf, blob.m_buf, cplen);
	free();

	m_buf = buf;
	m_size = cplen;

	return *this;
}

PWBlob&
PWBlob::operator = (const std::string& s)
{
	size_t cplen(s.size()+1);
	char* buf((char*)malloc(cplen));

	if ( NULL == buf )
	{
		return *this;
	}

	memcpy(buf, s.c_str(), cplen);
	free();

	m_buf = buf;
	m_size = cplen;

	return *this;
}

}; // namespace purewell

